<?php

/**
 * Данный класс представляет собой адаптер для обмена данными между "движком" gbook.php и СУБД MySQL
 *  
 * Класс содержит закрытые свойства, открытые и закрытые методы
 *
 * @author Massa
 */
class GbMySql {

	/**
  	 * Получает создаваемый объект класса
	 *
	 * @var GbMySql
	 */
	private $_db;

	/**
     * Конструктор объекта класса
     *
	 * Объект представляет собой открытое соединение с БД MySQL, с именем gbook и двумя таблицами: gb_messages и gb_comments 
	 * Создание объекта осуществляется путем выполнения серии запросов SQL
     * Подготовка запросов производится записью их текста в переменную $sql, а исполнение - вызовом метода queryHandle()
	 * Константы DB_HOST, DB_USER, DB_PASS, DB_NAME поступают в результате обработки ini-файла конфигурации (db_config.ini) служебным сценарием start.inc.php
     */
	public function __construct() {

		// Создание объекта класса GbMySql

		$this->_db = new mysqli(DB_HOST, DB_USER, DB_PASS);

		// Подключение к СУБД с проверкой на ошибки

		if ($this->_db->connect_errno) {
    		echo "Не могу подключиться к MySQLi: (" . $this->_db->connect_errno . ") " . $this->_db->connect_error;
		}

		// Создание БД, если она еще не была создана, с именем из константы DB_NAME
		// Параметрами задаются: набор символов UTF-8 и правило сортировки utf8_general_ci
		// Эти параметры необходимо задавать сразу, во избежание проблем в дальнейшем, когда в таблицах уже будет информация

		$sql = "CREATE DATABASE IF NOT EXISTS ". DB_NAME . " CHARACTER SET utf8 COLLATE utf8_general_ci";

		$result = $this->queryHandle($sql);

		// Переключение в контекст только что созданной БД

		$sql = "USE ". DB_NAME;

		$result = $this->queryHandle($sql);
		
		// Задание параметра для сохранения в БД информации в правильной кодировке UTF-8

		$sql = "SET NAMES utf8";

		$result = $this->queryHandle($sql);
						
		// Создание таблицы gb_messages, если еще не была создана, для хранения постов
		// Поля: id - главный ключ с автоинкрементом, name - имя пользователя, post - текст сообщения поста, datetime - время публикации в формате TIMESTAMP

		$sql = "CREATE TABLE IF NOT EXISTS gb_messages (
					id INT(11) NOT NULL auto_increment,
					PRIMARY KEY (id),
					name TEXT NOT NULL,
					post TEXT,
					datetime INT(11))";
				
		$result = $this->queryHandle($sql);

		// Создание таблицы gb_comments, если еще не была создана, для хранения комментариев
		// Поля: id - главный ключ с автоинкрементом, name - имя пользователя, comment - текст комментария, pid - идентификатор родительского поста - соответствует идентификатору поста таблицы gb_messages, datetime - время публикации в формате TIMESTAMP
		
		$sql = "CREATE TABLE IF NOT EXISTS gb_comments (
					id INT(11) NOT NULL auto_increment,
					PRIMARY KEY (id),
					name TEXT NOT NULL,
					comment TEXT,
					pid INT(11) NOT NULL,
					datetime INT(11))"; 

		$result = $this->queryHandle($sql);

	}

	/**
	 * Деструктор объекта класса
     *
	 * Объект уничтожается путем присвоения значения NULL содержащему его свойству
 	 */
	public function __destruct(){
		$this->_db = NULL;

	}

	/**
	 * Метод добавления поста в БД
     *
	 * Принимает имя пользователя ($name) и текст сообщения ($post) 
	 * Возвращает результат запроса на добавление строки в таблицу, true - успех, false - ошибка
     * Подготовка запроса производится записью его текста в переменную $sql, а исполнение - вызовом метода queryHandle()
	 *
	 * @param string $name
	 * @param string $post
	 * @return bool
 	 */
	public function postSave($name, $post) {

		// Очистка поступивших строк имени пользователя и текста сообщения: 
		// удаление тэгов, пробелов и служебных символов (таких как "\n"), защита экранированием вредоносных символов (addslashes),
		// а также, таких символов, как обратный слэш и кавычки  

		$name = $this->_db->real_escape_string(addslashes(trim(strip_tags($name))));
		$post = $this->_db->real_escape_string(addslashes(trim(strip_tags($post))));

		// Получение TIMESTAMP

		$dt = time();

		// Значения $name и $post взяты в кавычки, т.к. имеют строчный тип (требование SQL)
		
		$sql = "INSERT INTO gb_messages(
							name,
							post,
							datetime
						) VALUES (
							'$name',
							'$post',
							$dt)";
		return $this->queryHandle($sql);
		 
	}

	/**
	 * Метод обновления поста в БД
     *
	 * Принимает идентификатор поста ($id) и текст сообщения ($post) 
	 * Возвращает результат запроса на обновление записи в таблице, true - успех, false - ошибка
     * Подготовка запроса производится записью его текста в переменную $sql, а исполнение - вызовом метода queryHandle()
	 *
	 * @param integer $id
	 * @param string $post
	 * @return bool
 	 */
	public function postUpdate($id, $post) {

		// Приведение поступившего идентификатора поста к целому положительному типу

		$id = abs((int)$id);
		
		// Очистка поступившей строки текста сообщения: 
		// удаление тэгов, пробелов и служебных символов (таких как "\n"), защита экранированием вредоносных символов (addslashes),
		// а также, таких символов, как обратный слэш и кавычки 
		
		$post = $this->_db->real_escape_string(addslashes(trim(strip_tags($post))));

		// Значение $post взято в кавычки, т.к. имеет строчный тип (требование SQL)

		$sql = "UPDATE gb_messages SET
					post = '$post'
				WHERE
					id = $id";
	
		return $this->queryHandle($sql);
	}

	/**
	 * Метод получения всех постов из БД запросом SELECT
     *
     * Подготовка запроса производится записью его текста в переменную $sql, а исполнение - вызовом метода queryHandle()
	 *
	 * @return array
 	 */
	public function getAllPosts() {

		// Данные сортируются по убыванию идентификатора, т.е. в обратном порядке занесения в БД 

		$sql = "SELECT id, name, post, datetime FROM gb_messages ORDER BY id DESC";

		// Преобразование объекта в массив с помощью встроенного метода obj2Array() 

		return $this->obj2Array($this->queryHandle($sql));

	}

	/**
	 * Метод получения выбранного поста из БД
     *
	 * Принимает идентификатор поста ($id) 
	 * Возвращает результат запроса в виде массива значений поста
     * Подготовка запроса производится записью его текста в переменную $sql, а исполнение - вызовом метода queryHandle()
	 *
	 * @param integer $id
	 * @return array
 	 */
	public function getPost($id) {

		// Приведение поступившего идентификатора поста к целому положительному типу

		$id = abs((int)$id);	
	
		$sql = "SELECT name, post, datetime FROM gb_messages WHERE id = $id";

		// Преобразование объекта в массив с помощью встроенного метода obj2Array()

		return $this->obj2Array($this->queryHandle($sql));
	}

	/**
	 * Метод получения всех комментариев к выбранному посту из БД
     *
	 * Принимает идентификатор поста ($pid) 
	 * Возвращает результат запроса в виде массива полей комментариев
     * Подготовка запроса производится записью его текста в переменную $sql, а исполнение - вызовом метода queryHandle()
	 *
	 * @param integer $pid
	 * @return array
 	 */
	public function getAllComments($pid) {

		// Приведение поступившего идентификатора поста к целому положительному типу

		$pid = abs((int)$pid);	

		// Данные сортируются в порядке занесения комментариев в БД

		$sql = "SELECT id, name, comment, datetime FROM gb_comments WHERE pid = $pid ORDER BY id";

		// Преобразование объекта в массив с помощью встроенного метода obj2Array()

		return $this->obj2Array($this->queryHandle($sql));
	}

	/**
	 * Метод удаления выбранного поста из БД
     *
	 * Принимает идентификатор поста ($id) 
	 * Возвращает результат запроса на удаление записи в таблице, true - успех, false - ошибка
     * Подготовка запроса производится записью его текста в переменную $sql, а исполнение - вызовом метода queryHandle()
	 *
	 * @param integer $id
	 * @return bool
 	 */
	public function postDelete($id){

		// Приведение поступившего идентификатора поста к целому положительному типу

		$id = abs((int)$id);		

		$sql = "DELETE FROM gb_messages WHERE id = $id";
		
		return $this->queryHandle($sql);
	}

	/**
	 * Метод добавления комментария к выбранному посту в БД
     *
	 * Принимает имя пользователя ($name), текст комментария ($comment) и идентификатор поста ($pid) 
	 * Возвращает результат запроса на добавление записи в таблицу, true - успех, false - ошибка
     * Подготовка запроса производится записью его текста в переменную $sql, а исполнение - вызовом метода queryHandle()
	 *
	 * @param string $name
	 * @param string $comment
	 * @param integer $pid
	 * @return bool
 	 */
	public function commentAdd($name, $comment, $pid) {

		// Приведение поступившего идентификатора поста к целому положительному типу

		$pid = abs((int)$pid);		

		// Очистка поступивших строк имени пользователя и текста комментария: 
		// удаление тэгов, пробелов и служебных символов (таких как "\n"), защита экранированием вредоносных символов (addslashes),
		// а также, таких символов, как обратный слэш и кавычки

		$name = $this->_db->real_escape_string(addslashes(trim(strip_tags($name))));
		$comment = $this->_db->real_escape_string(addslashes(trim(strip_tags($comment))));

		// Получение TIMESTAMP

		$dt = time();

		// Значения $name и $comment взяты в кавычки, т.к. имеют строчный тип (требование SQL)

		$sql = "INSERT INTO gb_comments(
						name,
						comment,
						pid,
						datetime
					) VALUES (
						'$name',
						'$comment',
						$pid,
						$dt)";

		return $this->queryHandle($sql);
	}

	/**
	 * Метод удаления комментария/комментариев к выбранному посту в БД
     *
	 * Допускает удаление выбранного комментария или всех комментариев к заданному посту
	 * Принимает идентификатор комментария ($id) и идентификатор поста ($pid) 
	 * Возвращает результат запроса на удаление записи из таблицы, true - успех, false - ошибка
     * Подготовка запроса производится записью его текста в переменную $sql, а исполнение - вызовом метода queryHandle()
	 *
	 * @param integer $id
	 * @param integer $pid
	 * @return bool
 	 */
	public function commentRemove($id, $pid=0) {

		// Приведение поступивших идентификаторов поста к целому положительному типу

		$id = abs((int)$id);
		$pid = abs((int)$pid);		

		// Составление запроса на удаление в соответствии с условием:
		// если идентификатор поста не получен, т.е. $pid = 0 (по умолчанию)

		if (!$pid)		

		// удаляется один выбранный комментарий

			$sql = "DELETE FROM gb_comments WHERE id = $id";

		// если получен отличный от нуля идентификатор поста

		else

		// удаляются все комментарии к посту

			$sql = "DELETE FROM gb_comments WHERE pid = $pid";
		
		return $this->queryHandle($sql);
	}

	/**
	 * Закрытый метод обработки запросов к БД
     *
	 * Принимает текст запроса SQL ($qry) 
	 * Возвращает результат запроса в виде объекта (для запросов SELECT) или булева значения
     * Результат запроса проверяется на false (неудача)
	 *
	 * @param string $qry
	 * @return bool|obj
 	 */
	private function queryHandle($qry) {

		$res = $this->_db->query($qry);

		// В случае неудачи

			if (!$res) 

		// возвращается строка

				return "Запрос возвратил ошибку: (" . $this->_db->errno . ") " . $this->_db->error;

		// В случае удачи

			else

		// возвращается объект или true

				return $res;
	}

	/**
	 * Закрытый метод преобразования объекта, получаемого как результат запроса "SELECT", в массив
     *
	 * Принимает объект-результат запроса SQL ($obj) 
	 * Возвращает ассоциативный массив значений ($res) или false, в случае неудачи
	 *
	 * @param object $obj
	 * @return bool|array
 	 */
	private function obj2Array($obj) {

		// Проверка полученной переменной на принадлежность типу object

		if(is_object($obj))	{
			$res = array();
			while($row = $obj->fetch_assoc()){
				$res[] = $row;
			}
			return $res;
		}
		return false;
	}

}

?>
